<?php

namespace Modules\Common\Util;


use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Modules\Common\Models\BaseModel;

class Api
{
    const SUCCESS = 40000;//业务处理成功
    const FAIL = 40001;//业务处理失败，一般由业务逻辑导致

    //非业务性失败
    const TOKEN_EXPIRED = 40002;//token已过期
    const ILLEGAL_LOGIN = 40003;//非法登录
    const INVALID_INPUT = 40004;//输入不正确
    const OUT_SERVICE_UNAVAILABLE = 40005;//第三方服务不可用

    //...
    const SERVER_UNKNOWN = 40100;//未考虑到的异常

    /**
     *
     * @param null $data
     * @param string $msg
     * @param array $filters 例如['except' => 'token,token_expired_at', 'users' => ['except'=>'password']]
     * @return false|string
     */
    public static function success($data = null, $msg = '处理成功！', $filters = [])
    {
        return self::response(self::SUCCESS, $msg, $data, $filters);
    }

    public static function fail($msg = '处理失败', $data = null, $filters = [])
    {
        return self::response(self::FAIL, $msg, $data, $filters);
    }

    public static function illegalLogin()
    {
        return self::response(self::ILLEGAL_LOGIN, '拒绝服务!');
    }

    public static function validate($rules, $messages = [], $customAttributes = [])
    {
        Validator::validate(request()->all(), $rules, $messages, $customAttributes);
    }


    public static function validateNonRequestParams($data, $rules, $messages = [], $customAttributes = [])
    {
        Validator::validate($data, $rules, $messages, $customAttributes);
    }


    public static function response($code, $msg = '', $data = null, $filters = [])
    {
        if ($data instanceof BaseModel || $data instanceof Collection || $data instanceof LengthAwarePaginator) {
            $data = self::filterData($data, $filters);
        }

        return json_encode(['code' => $code, 'msg' => $msg, 'data' => $data], JSON_UNESCAPED_UNICODE);
    }


    public static function filterData($data, $filters)
    {
        $except = empty($filters['except']) ? [] : explode(',', $filters['except']);
        $only = empty($filters['only']) ? [] : explode(',', $filters['only']);
        $relationsFilter = Arr::except($filters, ['only', 'except']) ?: [];
        $filtered = [];
        if ($data instanceof BaseModel) {
            $filtered = self::doFilter($except, $only, $relationsFilter, $data);
        } elseif ($data instanceof Collection) {
            $filtered = $data->map(function ($item) use ($except, $only, $relationsFilter) {
                $data = self::doFilter($except, $only, $relationsFilter, $item);
                return $data;
            });
        } elseif ($data instanceof LengthAwarePaginator) {
            $filtered = $data->toArray();
            $arr = [];
            foreach ($filtered['data'] as $item) {
                $arr[] = self::doFilter($except, $only, $relationsFilter, $item);
            }
            $filtered['data'] = $arr;
        }
        return $filtered;
    }

    /**
     * 会全局过滤掉接口中返回的 'updated_at', 'deleted_at' 两个字段
     * @param $except
     * @param $only
     * @param $relationsFilter
     * @param $data
     * @return array
     */
    private static function doFilter($except, $only, $relationsFilter, $data)
    {
        if ($data instanceof BaseModel)
            $data = $data->toArray();
        // $exceptDefaults = ['updated_at', 'deleted_at', 'laravel_through_key'];
        $exceptDefaults = ['deleted_at', 'laravel_through_key'];
        $data = Arr::except($data, $exceptDefaults);
        if ($except) {
            $data = Arr::except($data, $except);
        } elseif ($only) {
            $data = Arr::only($data, $only);
        }
        if ($relationsFilter) {
            foreach ($relationsFilter as $relation => $filter) {
                if (is_array($data[$relation])) {
                    $data[$relation] = Arr::except($data[$relation], $exceptDefaults);
                    $except = empty($filter['except']) ? [] : explode(',', $filter['except']);
                    $only = empty($filter['only']) ? [] : explode(',', $filter['only']);
                    if ($except) {
                        $data[$relation] = Arr::except($data[$relation], $except);
                    } elseif ($only) {
                        $data[$relation] = Arr::only($data[$relation], $only);
                    }
                }

            }
        }
        return $data;
    }


}
